use diesel::{
    dsl::{Filter, Find},
    prelude::*,
    query_builder::IntoUpdateTarget,
    query_dsl::methods::{ExecuteDsl, FilterDsl, FindDsl},
};

use super::DeleteFindStatement;
use crate::database::DbError;

pub fn delete<'a, T, PK>(conn: &mut MysqlConnection, table: T, id: PK) -> Result<usize, DbError>
where
    T: FindDsl<PK>,
    Find<T, PK>: IntoUpdateTarget,
    DeleteFindStatement<Find<T, PK>>: ExecuteDsl<MysqlConnection>,
{
    let affected_rows = diesel::delete(table.find(id)).execute(conn)?;
    Ok(affected_rows)
}

pub fn deletes<'a, T, FilterExpr>(
    conn: &mut MysqlConnection,
    table: T,
    filter: FilterExpr,
) -> Result<usize, DbError>
where
    T: FilterDsl<FilterExpr>,
    Filter<T, FilterExpr>: IntoUpdateTarget,
    DeleteFindStatement<Filter<T, FilterExpr>>: ExecuteDsl<MysqlConnection>,
{
    let affected_rows = diesel::delete(table.filter(filter)).execute(conn)?;
    Ok(affected_rows)
}

#[macro_export]
macro_rules! db_delete {
    ($table:ident, $fn:ident) => {
        pub fn delete(conn: &mut MysqlConnection, id: i32) -> Result<usize, DbError> {
            let deleted_item = crud::delete::delete(conn, $table::table, id)?;
            Ok(deleted_item)
        }
    };
}

#[macro_export]
macro_rules! db_deletes {
    ($table:ident, $fn:ident) => {
        pub fn deletes(conn: &mut MysqlConnection, ids: Vec<i32>) -> Result<usize, DbError> {
            let deleted_item = crud::delete::deletes(conn, $table::table, $table::id.eq_any(ids))?;
            Ok(deleted_item)
        }
    };
}

#[macro_export]
macro_rules! test_db_delete {
    () => {
        #[test]
        fn test_delete() {
            let mut conn = establish_connection();
            conn.test_transaction::<_, diesel::result::Error, _>(|conn| {
                let (added_id, _, _) = insert_test_data(conn);
                let deleted_items = delete(conn, added_id).unwrap();
                assert_eq!(deleted_items, 1);
                let deleted_item = read(conn, added_id);
                assert!(deleted_item.is_err());
                Ok(())
            });
        }
    };
}
